//Copyright (c) 2009, Sandeep Datta
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are permitted provided 
//that the following conditions are met:
//
//* Redistributions of source code must retain the above copyright notice, this list of conditions and 
//the following disclaimer.
//
//* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//the following disclaimer in the documentation and/or other materials provided with the distribution.
//
//* Neither the name of Sandeep Datta nor the names of its contributors may be used to endorse or 
//promote products derived from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
//IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
//WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace SharpInstall
{
    class ArchiveFileProcessor
    {

        public static TableInfo GetTableInfoFromFile(string tableInfoFilePath)
        {
            return GetTableInfoFromStream(File.OpenRead(tableInfoFilePath));
        }

        public static TableInfo GetTableInfoFromStream(Stream tableInfoStream)
        {
            StreamReader reader = new StreamReader(tableInfoStream);

            string line = reader.ReadLine();

            string[] columnNames = line.Split('\t');

            line = reader.ReadLine();

            string[] columnDefs = line.Split('\t');

            line = reader.ReadLine();

            string[] thirdRowData = line.Split('\t');

            int codePage = 0;

            bool hasCodePageInfo = int.TryParse(thirdRowData[0], out codePage);

            int tableNameIndex = hasCodePageInfo ? 1 : 0;

            string tableName = thirdRowData[tableNameIndex];

            string[] primaryKeys = new string[thirdRowData.Length - (tableNameIndex + 1)];

            Array.Copy(thirdRowData, tableNameIndex + 1, primaryKeys, 0, primaryKeys.Length);

            ColumnInfo[] cols = new ColumnInfo[columnNames.Length];

            for (int i = 0; i < columnNames.Length; i++)
            {
                bool isPrimary = Array.IndexOf(primaryKeys, columnNames[i]) >= 0;
                cols[i] = new ColumnInfo(columnNames[i], ToDataTypeInfo(columnDefs[i], isPrimary));
            }

            TableInfo ti = new TableInfo(tableName, cols);

            return ti;
        }

        public static DataTypeInfo ToDataTypeInfo(string dataDef)
        {
            return ToDataTypeInfo(dataDef, false);
        }

        public static DataTypeInfo ToDataTypeInfo(string dataDef, bool isPrimary)
        {
            BaseDataType baseType;
            int maxLength;
            bool localizable;
            bool nullable;

            ParseDataDef(dataDef, out baseType, out maxLength, out localizable, out nullable);

            return new DataTypeInfo(baseType, maxLength, localizable, nullable, isPrimary);
        }

        private static void ParseDataDef(string dataDef
                                , out BaseDataType baseType
                                , out int maxLength
                                , out bool localizable
                                , out bool nullable)
        {
            dataDef = dataDef.Trim();

            maxLength = 0;
            localizable = false;
            nullable = false;

            switch (char.ToUpper(dataDef[0]))
            {
                case 'S':
                    baseType = BaseDataType.String;
                    localizable = false;
                    maxLength = int.Parse(dataDef.Substring(1));
                    break;
                case 'L':
                    baseType = BaseDataType.String;
                    localizable = true;
                    maxLength = int.Parse(dataDef.Substring(1));
                    break;
                case 'I':
                    if (dataDef[1] == '2')
                        baseType = BaseDataType.Int16;
                    else
                        baseType = BaseDataType.Int32;
                    break;
                case 'V':
                    baseType = BaseDataType.Binary;
                    maxLength = int.Parse(dataDef.Substring(1));
                    break;
                default:
                    throw new FormatException("Cannot parse data definition");
            }

            if (char.IsLower(dataDef[0]))
                nullable = false;
        }

    }
}
